package util;

public class Translator {
	private static final TranslationTable m_translationTable = new TranslationTable();

	/**
	 * Finds the complementary sequence in the binary alphabet and reverses it.
	 * 
	 * @param toBeComplementedAndReversed
	 *            the sequence to be complemented and reversed.
	 * 
	 * @return reversed complementary sequence to the given as parameter
	 *         sequence.
	 * 
	 * @throws IllegalArgumentException
	 */
	public String complementAndReverse(String toBeComplementedAndReversed) {
		String complemented = "";
		String reversed = "";

		for (int i = 0; i < toBeComplementedAndReversed.length(); i++) {
			String toComplement = toBeComplementedAndReversed.substring(i,
					i + 1);

			if (toComplement.equals("A")) {
				complemented = complemented.concat("G");
			} else {
				if (toComplement.equals("G")) {
					complemented = complemented.concat("A");
				} else {
					throw new IllegalArgumentException(
							"Unrecognized binary alphabet letter to be complemented..."
									+ toComplement);
				}
			}
		}

		for (int i = complemented.length() - 1; i >= 0; i--) {
			reversed = reversed.concat(complemented.substring(i, i + 1));
		}

		return reversed;
	}

	public String gcuTranslate(String toCheck) {
		int leng = toCheck.length();
		String toReturn = "";

		for (int i = 0; i < leng; i = i + 3) {
			toReturn = toReturn.concat("GCT");
		}

		return toReturn;
	}

	/**
	 * Finds the complementary sequence in the quadratrary (nucleotide) alphabet
	 * and reverses it.
	 * 
	 * @param toBeComplementedAndReversed
	 *            the sequence to be complemented and reversed.
	 * 
	 * @return reversed complementary sequence to the given as parameter
	 *         sequence.
	 * 
	 * @throws IllegalArgumentException
	 */
	public String complementAndReverseNucleotides(
			String toBeComplementedAndReversed) {
		String complemented = "";
		String reversed = "";

		for (int i = 0; i < toBeComplementedAndReversed.length(); i++) {
			String toComplement = toBeComplementedAndReversed.substring(i,
					i + 1);

			if (toComplement.equals("A")) {
				complemented = complemented.concat("T");
			} else {
				if (toComplement.equals("T")) {
					complemented = complemented.concat("A");
				} else {
					if (toComplement.equals("C")) {
						complemented = complemented.concat("G");
					} else {
						if (toComplement.equals("G")) {
							complemented = complemented.concat("C");
						} else {
							throw new IllegalArgumentException(
									"Unrecognized nucleotide alphabet letter to be complemented..."
											+ toComplement);
						}
					}
				}
			}
		}

		for (int i = complemented.length() - 1; i >= 0; i--) {
			reversed = reversed.concat(complemented.substring(i, i + 1));
		}

		return reversed;
	}

	/**
	 * Extracts out of the given as parameter DNA sequence (toBeExtracted) the
	 * wanted nucleotides (number) out of the triplets.
	 * 
	 * @param toBeExtracted
	 *            the sequence out of which the return string is extracted.
	 * @param number
	 *            the number of nucleotide in the triplet.
	 * 
	 * @return the extract out of the sequence , containing the extracted
	 *         nucleotides.
	 */
	public String extract(String toBeExtracted, int number) {
		String extracted = "";
		int i = 0;

		while (i < toBeExtracted.length()) {
			extracted = extracted.concat(toBeExtracted.substring(
					(i + number) - 1, i + number));
			i = i + 3;
		}

		return extracted;
	}

	/**
	 * .
	 * 
	 * @param toBeTranslated
	 * 
	 * @return
	 * 
	 * @throws IllegalArgumentException
	 */
	public String firstLetterTranslate(String toBeTranslated) {
		String translated = "";
		int i = 0;

		while (i < toBeTranslated.length()) {
			String toTranslate = toBeTranslated.substring(i, i + 1);

			if (checkLetterValidity(toTranslate.charAt(0))) {
				translated = translated.concat(m_translationTable
						.translate(toTranslate));
				i = i + 3;
			} else {
				throw new IllegalArgumentException(
						"Unrecognized triplet to be translated..."
								+ toTranslate);
			}
		}

		return translated;
	}

	/**
	 * .
	 * 
	 * @param toBeShuffled
	 * 
	 * @return
	 */
	public String frameShift(String toBeShuffled) {
		String toReturn = toBeShuffled.substring(1);

		return toReturn.concat(toBeShuffled.substring(0, 1));
	}

	/**
	 * Translates the given as parameter DNA sequence (toBeTranslated) to binary
	 * alphabet using the translation table (single letters are translated).
	 * 
	 * @param toBeTranslated
	 *            the sequence to be translated.
	 * 
	 * @return the translated DNA sequence in binary alphabet language.
	 * 
	 * @throws IllegalArgumentException
	 *             in case the sequence to be translated contains illegal
	 *             triplets.
	 */
	public String letterTranslate(String toBeTranslated) {
		String translated = "";
		int i = 0;

		while (i < toBeTranslated.length()) {
			String toTranslate = toBeTranslated.substring(i, i + 1);

			if (checkLetterValidity(toTranslate.charAt(0))) {
				translated = translated.concat(m_translationTable
						.translate(toTranslate));
				i = i + 1;
			} else {
				throw new IllegalArgumentException(
						"Unrecognized triplet to be translated..."
								+ toTranslate);
			}
		}

		return translated;
	}

	/**
	 * .
	 * 
	 * @param toBeTranslated
	 * 
	 * @return
	 * 
	 * @throws IllegalArgumentException
	 */
	public String secondLetterTranslate(String toBeTranslated) {
		String translated = "";
		int i = 1;

		while (i < toBeTranslated.length()) {
			String toTranslate = toBeTranslated.substring(i, i + 1);

			if (checkLetterValidity(toTranslate.charAt(0))) {
				translated = translated.concat(m_translationTable
						.translate(toTranslate));
				i = i + 3;
			} else {
				throw new IllegalArgumentException(
						"Unrecognized triplet to be translated..."
								+ toTranslate);
			}
		}

		return translated;
	}

	public String complementAndReverseWithN(String word, String codon) {
		String toReturn = "";
		String toReturn2 = "";
		String nLetter = tripletTranslate(codon);
		String wordWithoutN = word.replaceAll("N", nLetter);
		toReturn = complementAndReverse(wordWithoutN);
		int x = 6;
		for (int i = 0; i < word.length(); i++) {
			if (word.substring(i, i + 1).equals("N")) {
				toReturn2.concat(toReturn.substring(i, i + 1));
			}

		}
		return toReturn;
	}

	public String octamerTranslate(String octamer) {
		String answer = "";

		for (int i = 0; i < octamer.length(); i++) {
			answer += m_translationTable.translateAa(octamer
					.substring(i, i + 1));
		}

		return answer;
	}

	public String thirdLetterTranslate(String toBeTranslated) {
		String translated = "";
		int i = 2;

		while (i < toBeTranslated.length()) {
			String toTranslate = toBeTranslated.substring(i, i + 1);

			if (checkLetterValidity(toTranslate.charAt(0))) {
				translated = translated.concat(m_translationTable
						.translate(toTranslate));
				i = i + 3;
			} else {
				throw new IllegalArgumentException(
						"Unrecognized triplet to be translated..."
								+ toTranslate);
			}
		}

		return translated;
	}

	public String aaTranslate(String toBeTranslated) {
		String translated = "";
		int i = 0;

		while (i < toBeTranslated.length()) {
			String toTranslate = toBeTranslated.substring(i, i + 1);

			if (!toTranslate.equals("S")) {
				translated = translated.concat(m_translationTable
						.translateAa(toTranslate));
				i = i + 1;
			} else if (toTranslate.equals("S")) {
				double x= Math.random();
				if (x<(1.0/3.0)){
					translated = translated.concat("G");
				}else{
					translated = translated.concat("A");
				}				
				i = i + 1;
			}else
				throw new IllegalArgumentException(
						"Unrecognized triplet to be translated..."
								+ toTranslate);
			
		}

		return translated;
	}

	/**
	 * Translates the given as parameter DNA sequence (toBeTranslated) to binary
	 * alphabet using the translation table (triplets are translated).
	 * 
	 * @param toBeTranslated
	 *            the sequence to be translated.
	 * 
	 * @return the translated DNA sequence in binary alphabet language.
	 * 
	 * @throws IllegalArgumentException
	 *             in case the sequence to be translated contains illegal
	 *             triplets.
	 */
	public String tripletTranslate(String toBeTranslated) {
		String translated = "";
		int i = 0;

		while (i < toBeTranslated.length()) {
			String toTranslate = toBeTranslated.substring(i, i + 3);

			if (checkTripletValidity(toTranslate)) {
				translated = translated.concat(m_translationTable
						.translate(toTranslate));
				i = i + 3;
			} else {
				throw new IllegalArgumentException(
						"Unrecognized triplet to be translated..."
								+ toTranslate);
			}
		}

		return translated;
	}

	private boolean forbiddenAA(String triplet, String[] forbidden) {
		boolean flag = false;
		for (int i = 0; i < forbidden.length; i++)
			if (forbidden[i].equals(triplet))
				flag = true;

		return flag;
	}

	public String specialTripletTranslate(String toBeTranslated,
			String[] forbidden) {
		String translated = "";
		int i = 0;

		while (i < toBeTranslated.length()) {
			String toTranslate = toBeTranslated.substring(i, i + 3);

			if (checkTripletValidity(toTranslate)) {
				if (forbiddenAA(toTranslate, forbidden)) {
					translated = translated.concat("N");
				} else {
					translated = translated.concat(m_translationTable
							.translate(toTranslate));
				}
				i = i + 3;
			} else {
				throw new IllegalArgumentException(
						"Unrecognized triplet to be translated..."
								+ toTranslate);
			}
		}
		return translated;
	}

	/**
	 * Check the validity of the letter x translator should work with.
	 * 
	 * @param x
	 *            the letter that should be checked for validity.
	 * 
	 * @return true in case the letter is valid ( is one of the {A,T,G,C}
	 *         letters),false otherwise.
	 */
	private boolean checkLetterValidity(char x) {
		return ((x == 'A') || (x == 'T') || (x == 'C') || (x == 'G'));
	}

	/**
	 * Check the validity of the triplet x the translator should translate.
	 * 
	 * @param x
	 *            the triplet that should be translated.
	 * 
	 * @return true in case the triplet is valid (is a triplet build of
	 *         {A,T,G,C} alphabet, false otherwise.
	 */
	private boolean checkTripletValidity(String x) {
		if (x.length() != 3) {
			return false;
		} else {
			for (int i = 0; i < 3; i++) {
				if (!checkLetterValidity(x.charAt(i))) {
					return false;
				}
			}
		}

		return true;
	}

}
